/*
 *   SSCatalystDocumentData.m
 *  MESLib
 * 
 * Copyright 2003-2009 Starline Software Ltd
 * 
 * This file is part of MESLib.
 * 
 * MESLib is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MESLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with MESLib. If not, see <http://www.gnu.org/licenses/>.
 * Created by Tobias Haughton on Sat Jan 25 2003.
*/
//SSCatalystDocumentData holds all data related to a chart

#import "SSCatalystDocumentData.h"
#import "SSCatalystDocument.h"
#import "SSNeedsDiamondsPanelController.h"
#import "SSCatalystAppController.h"

@implementation SSCatalystDocumentData

- (id)initWithDocument:(SSCatalystDocument *)document
{
   if (self = [super init]) {
      theDocument = document;
      NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
      structureDictionary = [[NSMutableDictionary alloc] init];
 
      [structureDictionary setObject:[NSString string] forKey:@"fileName"];
      [structureDictionary setObject:[[SSChartDate calendarDate] descriptionWithCalendarFormat:@"%y%m%d%H%M%F"] forKey:@"unique_id"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultTitleKey] forKey:@"title"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultAuthorKey] forKey:@"author"];
      [structureDictionary setObject:[NSCalendarDate dateWithTimeIntervalSinceReferenceDate:[[defaults objectForKey:SSDefaultDateKey] timeIntervalSinceReferenceDate]] forKey:@"chartDate"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultProjectFolderKey] forKey:@"projectFolder"];
      [structureDictionary setObject:[NSMutableArray array] forKey:@"referencedEventBlocks"];
      [structureDictionary setObject:[NSMutableArray array] forKey:@"comments"];
      [structureDictionary setObject:[NSMutableArray array] forKey:@"needsDiamonds"];
      [structureDictionary setObject:[NSMutableArray array] forKey:@"subDirectories"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultWhiteLabelDesignationKey] forKey:@"whiteColorDesignation"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultYellowLabelDesignationKey] forKey:@"yellowColorDesignation"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultGreenLabelDesignationKey] forKey:@"greenColorDesignation"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultLightBlueLabelDesignationKey] forKey:@"lightBlueColorDesignation"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultBlueLabelDesignationKey] forKey:@"blueColorDesignation"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultPurpleLabelDesignationKey] forKey:@"purpleColorDesignation"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultOrangeLabelDesignationKey] forKey:@"orangeColorDesignation"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultRedLabelDesignationKey] forKey:@"redColorDesignation"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue1Key] forKey:@"diamondUDValue1"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue2Key] forKey:@"diamondUDValue2"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue3Key] forKey:@"diamondUDValue3"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue4Key] forKey:@"diamondUDValue4"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue5Key] forKey:@"diamondUDValue5"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue6Key] forKey:@"diamondUDValue6"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondOptionUDValue1Key] forKey:@"diamondOptionUDValue1"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondOptionUDValue2Key] forKey:@"diamondOptionUDValue2"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondOptionUDValue3Key] forKey:@"diamondOptionUDValue3"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondOptionUDValue4Key] forKey:@"diamondOptionUDValue4"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondOptionUDValue5Key] forKey:@"diamondOptionUDValue5"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondTradeoffUDValue1Key] forKey:@"diamondTradeoffUDValue1"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondTradeoffUDValue2Key] forKey:@"diamondTradeoffUDValue2"];
      [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondTradeoffUDValue3Key] forKey:@"diamondTradeoffUDValue3"];
      [structureDictionary setObject:[NSMutableArray array] forKey:@"poisonWords"];
      
      aalosDictionary = [[NSMutableDictionary alloc] init];
      NSMutableDictionary *actionDictionary = [NSMutableDictionary dictionary];
      NSMutableDictionary *actorDictionary = [NSMutableDictionary dictionary];
      NSMutableDictionary *locationDictionary = [NSMutableDictionary dictionary];
      NSMutableDictionary *sourceDictionary = [NSMutableDictionary dictionary];
      NSMutableDictionary *objectDictionary = [NSMutableDictionary dictionary];
      NSMutableDictionary *remarkDictionary = [NSMutableDictionary dictionary];
      [aalosDictionary setObject:actionDictionary forKey:@"action"];
      [aalosDictionary setObject:actorDictionary forKey:@"actor"];
      [aalosDictionary setObject:locationDictionary forKey:@"location"];
      [aalosDictionary setObject:sourceDictionary forKey:@"source"];
      [aalosDictionary setObject:objectDictionary forKey:@"object"];
      [aalosDictionary setObject:remarkDictionary forKey:@"remark"];

      dataSourceDictionary = [[NSMutableDictionary alloc] init];
      NSMutableArray *actionArray = [NSMutableArray array];
      NSMutableArray *actorArray = [NSMutableArray array];
      NSMutableArray *locationArray = [NSMutableArray array];
      NSMutableArray *sourceArray = [NSMutableArray array];
      NSMutableArray *objectArray = [NSMutableArray array];
      NSMutableArray *remarkArray = [NSMutableArray array];
      [dataSourceDictionary setObject:actionArray forKey:@"action"];
      [dataSourceDictionary setObject:actorArray forKey:@"actor"];
      [dataSourceDictionary setObject:locationArray forKey:@"location"];
      [dataSourceDictionary setObject:sourceArray forKey:@"source"];
      [dataSourceDictionary setObject:objectArray forKey:@"object"];
      [dataSourceDictionary setObject:remarkArray forKey:@"remark"];

      alphabeticDataSourceDictionary = [[NSMutableDictionary alloc] init];
      NSMutableArray *alphActionArray = [NSMutableArray array];
      NSMutableArray *alphActorArray = [NSMutableArray array];
      NSMutableArray *alphLocationArray = [NSMutableArray array];
      NSMutableArray *alphSourceArray = [NSMutableArray array];
      NSMutableArray *alphObjectArray = [NSMutableArray array];
      NSMutableArray *alphRemarkArray = [NSMutableArray array];
      [alphabeticDataSourceDictionary setObject:alphActionArray forKey:@"action"];
      [alphabeticDataSourceDictionary setObject:alphActorArray forKey:@"actor"];
      [alphabeticDataSourceDictionary setObject:alphLocationArray forKey:@"location"];
      [alphabeticDataSourceDictionary setObject:alphSourceArray forKey:@"source"];
      [alphabeticDataSourceDictionary setObject:alphObjectArray forKey:@"object"];
      [alphabeticDataSourceDictionary setObject:alphRemarkArray forKey:@"remark"];

      defaultNeedsDiamondValues = [[NSMutableDictionary alloc] init];
      [defaultNeedsDiamondValues setObject:[NSString string] forKey:@"analyst"];
      [defaultNeedsDiamondValues setObject:[NSString string] forKey:@"fileID"];

      [self setEventArray:[NSMutableArray array]];
      [self setCommentArray:[NSMutableArray array]];
      [self setNeedsDiamondArray:[NSMutableArray array]];
      
      actorColumnWidth = [[[[NSScreen mainScreen] deviceDescription] objectForKey:NSDeviceResolution] sizeValue].width * 0.8;
      displayMode = SSMatrixDisplayMode;
      overlapUnit = SSDayUnit;
      overlapPixelsPerUnit = 10.0;
      currentLinkFromEvent = nil;
      
      [self updateFilteredActorArray];
   }
   return self;
}

- (NSMutableArray *)eventArray
{
   return eventArray;
}

- (NSMutableArray *)allEventsInStructure:(NSMutableDictionary *)dict
{
   //builds an array of all events in dict and nested structure dictionaries
   NSMutableArray *array = [NSMutableArray array];
   NSEnumerator *enumerator = [[dict objectForKey:@"subDirectories"] objectEnumerator];
   id anObject;

   [array addObjectsFromArray:[dict objectForKey:@"referencedEventBlocks"]];

   while (anObject = [enumerator nextObject]) {
      //go through our subDirectories and get their events
      [array addObjectsFromArray:[self allEventsInStructure:anObject]];
   }

   return array;
}

- (NSMutableArray *)commentArray
{
   return commentArray;
}

- (NSMutableArray *)allCommentsInStructure:(NSMutableDictionary *)dict
{
   //builds an array of all comments in dict and nested structure dictionaries
   NSMutableArray *array = [NSMutableArray array];
   NSEnumerator *enumerator = [[dict objectForKey:@"subDirectories"] objectEnumerator];
   id anObject;

   [array addObjectsFromArray:[dict objectForKey:@"comments"]];

   while (anObject = [enumerator nextObject]) {
      //go through our subDirectories and get their comments
      [array addObjectsFromArray:[self allCommentsInStructure:anObject]];
   }

   return array;
}

- (NSMutableArray *)needsDiamondArray
{
   return needsDiamondArray;
}

- (NSMutableArray *)allNeedsDiamondsInStructure:(NSMutableDictionary *)dict
{
   //builds an array of all diamonds in dict and nested structure dictionaries
   NSMutableArray *array = [NSMutableArray array];
   NSEnumerator *enumerator = [[dict objectForKey:@"subDirectories"] objectEnumerator];
   id anObject;

   [array addObjectsFromArray:[dict objectForKey:@"needsDiamonds"]];

   while (anObject = [enumerator nextObject]) {
      //go through our subDirectories and get their diamonds
      [array addObjectsFromArray:[self allNeedsDiamondsInStructure:anObject]];
   }

   return array;
}

- (NSMutableDictionary *)aalosDictionary
{
   return aalosDictionary;   
}

- (NSMutableDictionary *)structureDictionary
{
   return structureDictionary;
}

- (id)structureObjectForKey:(NSString *)key
{
   return [structureDictionary objectForKey:key];
}

- (void)removeAllTracesOfStructureDict:(NSMutableDictionary *)dict
{
   NSEnumerator *enumerator;
   id anObject;

   //remove all oft he events
   enumerator = [[self allEventsInStructure:dict] objectEnumerator];
   while (anObject = [enumerator nextObject]) {
      [theDocument deleteObject:anObject];
   }

   //remove all comments
   enumerator = [[self allCommentsInStructure:dict] objectEnumerator];
   while (anObject = [enumerator nextObject]) {
      [theDocument deleteObject:anObject];
   }

   //remove the imported structure dictionary
   [[[self structureDictionary] objectForKey:@"subDirectories"] removeObjectIdenticalTo:dict];
}


- (void)addEventsFromArray:(NSMutableArray *)array
{
   NSEnumerator *enumerator = [array objectEnumerator];
   id anObject;
   NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

   while (anObject = [enumerator nextObject]) {
      if([self eventWithUniqueId:[anObject unique_id]]) {
         //there is already an event with this ID change it
         SSChartDate *now = [SSChartDate calendarDate];
         [anObject setUnique_id:[NSString stringWithFormat:@"%@%@", [anObject actor], [now descriptionWithCalendarFormat:@"%y%m%d%H%M%F"]]];
      }

      [eventArray addObject:anObject];
      [self addEventToAalosDictionary:anObject];

      //register for notifications from this event
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeActorEntry:)
                 name:@"SSActorChanged"
               object:anObject];
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeActionEntry:)
                 name:@"SSActionChanged"
               object:anObject];
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeLocationEntry:)
                 name:@"SSLocationChanged"
               object:anObject];
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeSourceEntry:)
                 name:@"SSSourceChanged"
               object:anObject];
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeObjectEntry:)
                 name:@"SSObjectChanged"
               object:anObject];
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeRemarkEntry:)
                 name:@"SSRemarkChanged"
               object:anObject];
      [self validateNewEventBeginTime:anObject];
      [[theDocument undoManager] registerUndoWithTarget:theDocument selector:@selector(deleteObject:) object:anObject]; //for undo
   }
   
   [self updateFilteredActorArray];
}

- (void)addEventToDocument:(SSEventObject *)event structureDictionary:(NSMutableDictionary *)dict
{
   if(!dict) {
      dict = structureDictionary;
   }

   if(![(SSCatalystAppController *)[NSApp delegate] isRegistered] && [[self eventArray] count] >= 20) {
      //if the user is not registered then limit the number of EBs to 20
      NSRunAlertPanel(NSLocalizedString(@"UnableToPerformAction", nil), NSLocalizedString(@"EvaluationEBLimitExceeded", nil), @"OK", nil, nil, nil);
      
      return;
   }
   
   if([self eventWithUniqueId:[event unique_id]]) {
      //there is already an event with this ID change it
      SSChartDate *now = [SSChartDate calendarDate];
      [event setUnique_id:[NSString stringWithFormat:@"%@%@", [event actor], [now descriptionWithCalendarFormat:@"%y%m%d%H%M%F"]]];
   }

   [[dict objectForKey:@"referencedEventBlocks"] addObject:event];
   [eventArray addObject:event];
   [self addEventToAalosDictionary:event];
   [self updateFilteredActorArray];
   [theDocument addEventToChartView:event];

   //register for notifications from this event
   NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
   [nc addObserver:self
          selector:@selector(aalosDictionaryChangeActorEntry:)
              name:@"SSActorChanged"
            object:event];
   [nc addObserver:self
          selector:@selector(aalosDictionaryChangeActionEntry:)
              name:@"SSActionChanged"
            object:event];
   [nc addObserver:self
          selector:@selector(aalosDictionaryChangeLocationEntry:)
              name:@"SSLocationChanged"
            object:event];
   [nc addObserver:self
          selector:@selector(aalosDictionaryChangeSourceEntry:)
              name:@"SSSourceChanged"
            object:event];
   [nc addObserver:self
          selector:@selector(aalosDictionaryChangeObjectEntry:)
              name:@"SSObjectChanged"
            object:event];
   [nc addObserver:self
          selector:@selector(aalosDictionaryChangeRemarkEntry:)
              name:@"SSRemarkChanged"
            object:event];

   [[theDocument undoManager] registerUndoWithTarget:theDocument selector:@selector(deleteObject:) object:event]; //for undo

   [[NSNotificationCenter defaultCenter] postNotificationName:@"SSEventAddedToDocument"
                                                       object:nil];

   [theDocument reload]; //reload the table so that a new row is displayed if needed

   [theDocument updateChangeCount:NSChangeDone];
}

- (void)removeEventFromDocument:(SSEventObject *)event
{
   NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

   [nc removeObserver:self
                 name:@"SSActorChanged"
               object:event];
   [nc removeObserver:self
                 name:@"SSActionChanged"
               object:event];
   [nc removeObserver:self
                 name:@"SSLocationChanged"
               object:event];
   [nc removeObserver:self
                 name:@"SSSourceChanged"
               object:event];
   [nc removeObserver:self
                 name:@"SSObjectChanged"
               object:event];
   [nc removeObserver:self
                 name:@"SSRemarkChanged"
               object:event];

   //remove the event from the aalosDictionary
   [self aalosDictionaryRemoveEvent:event fromDictWithKey:@"actor"];
   [self aalosDictionaryRemoveEvent:event fromDictWithKey:@"action"];
   [self aalosDictionaryRemoveEvent:event fromDictWithKey:@"location"];
   [self aalosDictionaryRemoveEvent:event fromDictWithKey:@"source"];
   [self aalosDictionaryRemoveEvent:event fromDictWithKey:@"object"];
   [self aalosDictionaryRemoveEvent:event fromDictWithKey:@"remark"];

   //remove all related needs diamonds
   NSEnumerator *enumerator = [[event allRelatedNeedsDiamonds] objectEnumerator];
   id anObject;
   while (anObject = [enumerator nextObject]) {
      [self removeNeedsDiamondFromDocument:anObject];
   }
   
   //tell the event to remove links
   [event removeAllLinks];
   
   //remove the event from the event array
   [[self eventArray] removeObjectIdenticalTo:event];

   //remove the event from structure dict
   NSMutableDictionary *dict = [self structureDictionaryForObject:event];
   if(dict) {
      [[dict objectForKey:@"referencedEventBlocks"] removeObjectIdenticalTo:event];
   }
   
   [self updateFilteredActorArray];

   [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
}


- (void)addEventToAalosDictionary:(SSEventObject *)event
{
   [self addEventToAalosDictionary:event forKey:@"action"];
   [self addEventToAalosDictionary:event forKey:@"actor"];
   [self addEventToAalosDictionary:event forKey:@"location"];
   [self addEventToAalosDictionary:event forKey:@"object"];
   [self addEventToAalosDictionary:event forKey:@"source"];
   [self addEventToAalosDictionary:event forKey:@"remark"];
}

- (void)addEventToAalosDictionary:(SSEventObject *)event forKey:(NSString *)key
{
   SEL theMethodSelector = NSSelectorFromString(key); //get a selector from key so that we can call the correct method from the event object

   if([key isEqualToString:@"source"]) {
      //we are adding source so there's a bit more work to do
      NSArray *sourceArray = [event performSelector:theMethodSelector];
      int i = 0;
      while(i < [sourceArray count]) {
         if([[aalosDictionary objectForKey:key] objectForKey:[sourceArray objectAtIndex:i]]) {
            //there is already and array for this value so just add the events unique id
            [[[aalosDictionary objectForKey:key] objectForKey:[sourceArray objectAtIndex:i]] addObject:[event unique_id]];
         } else {
            //no array for this value so create one and add the events unique id
            NSMutableArray *array = [NSMutableArray array];
            [array addObject:[event unique_id]];
            [[aalosDictionary objectForKey:key] setObject:array forKey:[sourceArray objectAtIndex:i]];
            //add this value to the datasource so that we have the value in table and combo boxes
            [self dataSourceDictionaryArrayWithKey:key addString:[sourceArray objectAtIndex:i]];
         }
         i++;
      }      
   } else {
      //just add the string
      if([[aalosDictionary objectForKey:key] objectForKey:[event performSelector:theMethodSelector]]) {
         //there is already and array for this value so just add the events unique id
         [[[aalosDictionary objectForKey:key] objectForKey:[event performSelector:theMethodSelector]] addObject:[event unique_id]];
      } else {
         //no array for this value so create one and add the events unique id
         NSMutableArray *array = [NSMutableArray array];
         [array addObject:[event unique_id]];
         [[aalosDictionary objectForKey:key] setObject:array forKey:[event performSelector:theMethodSelector]];
         //add this value to the datasource so that we have the value in table and combo boxes
         [self dataSourceDictionaryArrayWithKey:key addString:[event performSelector:theMethodSelector]];
      }
   }
}

- (void)orderActorsBasedOnArray:(NSMutableArray *)orderArray
{
   //orders our actors in dataSourceDictionary based on order array
   //order array should contain nsdictionaries containg two objects "row" and "name"
   NSMutableArray *actorArray = [dataSourceDictionary objectForKey:@"actor"];
   NSMutableArray *sortedActorArray = [NSMutableArray array];
   NSEnumerator *dictEnumerator = [orderArray objectEnumerator];
   NSMutableDictionary *dictObject;
   NSEnumerator *sortedEnumerator;
   NSString *anObject;
   int index = 0;

   while (dictObject = [dictEnumerator nextObject]) {
      //build an array based on the orderArray with values from actorArray
      if([actorArray containsObject:[dictObject objectForKey:@"name"]]) {
         [sortedActorArray addObject:[[dictObject objectForKey:@"name"] copy]]; //add this actor to the sorted array
         [actorArray removeObject:[dictObject objectForKey:@"name"]]; //remove the actor from the actor array
      }
   }

   //there could be actors left which weren't referenced in the structure file. To deal with this we will sort the actorArray
   //based on the alphabet and then add the properly sorted actors in sortedActorArray starting at index 0
   //this will give us an array with all specified actors in the correct order and any unspecified actors sorted alphabetically at the end
   [actorArray sortUsingSelector:@selector(caseInsensitiveCompare:)];

   sortedEnumerator = [sortedActorArray objectEnumerator];
   while (anObject = [sortedEnumerator nextObject]) {
      //insert the actors at correct position
      [actorArray insertObject:anObject atIndex:index];
      index++;
   }

   [self updateFilteredActorArray];
}

- (void)orderActorsForImportedFileBasedOnArray:(NSMutableArray *)orderArray
{
   //orders our actors in dataSourceDictionary based on order array
   //order array should contain nsdictionaries containg two objects "row" and "name"
   NSMutableArray *actorArray = [dataSourceDictionary objectForKey:@"actor"];
   NSMutableArray *sortedActorArray = [NSMutableArray array];
   NSEnumerator *dictEnumerator = [orderArray objectEnumerator];
   NSMutableDictionary *dictObject;

   while (dictObject = [dictEnumerator nextObject]) {
      //build an array based on the orderArray with values from actorArray
      if([actorArray containsObject:[dictObject objectForKey:@"name"]]) {
         if([actorArray indexOfObject:[dictObject objectForKey:@"name"]] > ([actorArray count] - [orderArray count])) { //the actor is there and it is in the right position, if this fails the actor was already present when we imported the file so we don't want to change its order
            [sortedActorArray addObject:[[dictObject objectForKey:@"name"] copy]]; //add this actor to the sorted array
            [actorArray removeObject:[dictObject objectForKey:@"name"]]; //remove the actor from the actor array
         }
      }
   }

   [actorArray addObjectsFromArray:sortedActorArray];
}

- (NSString *)addressForNewEvent
{
   //create and return an address based on the number of events
   NSMutableString *address = [NSMutableString string];
   int number = [[structureDictionary objectForKey:@"referencedEventBlocks"] count]; //start at the number of events
   NSNumber *num;
   NSString *numString;

   do {
      //loop through and keep incrementing the address number until we find one which isn't used
      number++;
      [address setString:@"000000.xml"];
      num = [NSNumber numberWithInt:number];
      numString = [num stringValue];

      [address replaceCharactersInRange:NSMakeRange(([address length] - ([numString length] + 4)), [numString length]) withString:numString];
   } while([self hasEventForAddress:address inStructureDictionary:structureDictionary]);

   return address;
}

- (BOOL)hasEventForAddress:(NSString *)address inStructureDictionary:(NSMutableDictionary *)dict
{
   NSEnumerator *enumerator = [[dict objectForKey:@"referencedEventBlocks"] objectEnumerator];
   SSEventObject *anObject;

   if(enumerator) {
      while (anObject = [enumerator nextObject]) {         
         if([[anObject address] isEqualToString:address]) {
            //this event is using the address
            return YES;
         }
      }
   }

   return NO; //no event with this address
}

- (void)aalosDictionaryChangeActorEntry:(NSNotification *)note
{
   NSString *oldActorName = [self aalosDictionaryKeyForEventWithUniqueId:[[note object] unique_id] inDictForKey:@"actor"];
   int row = [self dataSourceDictionaryIndexOfObject:oldActorName inArray:@"actor"]; //get the row that this actor was in
   [self aalosDictionaryRemoveEvent:[note object] fromDictWithKey:@"actor"];
   [self addEventToAalosDictionary:[note object] forKey:@"actor"];
   if([[[aalosDictionary objectForKey:@"actor"] objectForKey:[[note object] actor]] count] == 1) {//if this is not true the eb will move to the position of this row as set by user
      //there is no existing row for the new actor so either put it one row below it's old row or replace the old row
      if([[dataSourceDictionary objectForKey:@"actor"] indexOfObject:oldActorName] != NSNotFound) {
         //there is still a row for the old actor put it 1 row down
         [self dataSourceDictionaryArrayWithKey:@"actor" moveObjectsAtIndexes:
[NSArray arrayWithObjects:[NSNumber numberWithInt:[self dataSourceDictionaryIndexOfObject:[[note object] actor] inArray:@"actor"]], nil] toIndex:row+1];
      } else {
         //the row which this EB was on is going to be removed so add the EB to the old row index
         [self dataSourceDictionaryArrayWithKey:@"actor" moveObjectsAtIndexes:
[NSArray arrayWithObjects:[NSNumber numberWithInt:[self dataSourceDictionaryIndexOfObject:[[note object] actor] inArray:@"actor"]], nil] toIndex:row];
      }
   }

   [self updateFilteredActorArray];
   [theDocument reload]; //the table contents are probably different
}

- (void)aalosDictionaryChangeActionEntry:(NSNotification *)note
{
   [self aalosDictionaryRemoveEvent:[note object] fromDictWithKey:@"action"];
   [self addEventToAalosDictionary:[note object] forKey:@"action"];
}

- (void)aalosDictionaryChangeLocationEntry:(NSNotification *)note
{
   [self aalosDictionaryRemoveEvent:[note object] fromDictWithKey:@"location"];
   [self addEventToAalosDictionary:[note object] forKey:@"location"];
}

- (void)aalosDictionaryChangeSourceEntry:(NSNotification *)note
{
   [self aalosDictionaryRemoveEvent:[note object] fromDictWithKey:@"source"];
   [self addEventToAalosDictionary:[note object] forKey:@"source"];
}

- (void)aalosDictionaryChangeObjectEntry:(NSNotification *)note
{
   [self aalosDictionaryRemoveEvent:[note object] fromDictWithKey:@"object"];
   [self addEventToAalosDictionary:[note object] forKey:@"object"];
}

- (void)aalosDictionaryChangeRemarkEntry:(NSNotification *)note
{
   [self aalosDictionaryRemoveEvent:[note object] fromDictWithKey:@"remark"];
   [self addEventToAalosDictionary:[note object] forKey:@"remark"];
}

- (void)aalosDictionaryRemoveEvent:(SSEventObject *)event fromDictWithKey:(NSString *)key
{
   NSMutableDictionary *dict = [aalosDictionary objectForKey:key]; //dict for key eg source, actor etc
   NSString *eventKey;
   NSMutableArray *array;
      
   if(dict) {
      if([key isEqualToString:@"source"]) {
         //it a source so we may need to remove multiple values
         while(eventKey = [self aalosDictionaryKeyForEventWithUniqueId:[event unique_id] inDictForKey:key]) {
            array = [dict objectForKey:eventKey]; //get the sub array which cntains this event

            if(array) {
               [array removeObject:[event unique_id]]; //remove this events unique id
               if([array count] == 0) {
                  //this was the only event with that value so remove array from dictionary
                  [dict removeObjectForKey:eventKey];
                  [self dataSourceDictionaryArrayWithKey:key removeString:eventKey];
               }
            }
         }
      } else {
         //there is only 1 value to remove
         eventKey = [self aalosDictionaryKeyForEventWithUniqueId:[event unique_id] inDictForKey:key];
         array = [dict objectForKey:eventKey]; //get the sub array which cntains this event

         if(array) {
            [array removeObject:[event unique_id]]; //remove this events unique id
            if([array count] == 0) {
               //this was the only event with that value so remove array from dictionary
               [dict removeObjectForKey:eventKey];
               [self dataSourceDictionaryArrayWithKey:key removeString:eventKey];
            }
         }
      }
   }
}

- (NSString *)aalosDictionaryKeyForEventWithUniqueId:(NSString *)unique inDictForKey:(NSString *)key
{
   NSMutableDictionary *dict = [aalosDictionary objectForKey:key];
   NSEnumerator *dictEnumerator = [dict objectEnumerator];
   NSEnumerator *arrayEnumerator;
   id arrayObject;
   id idObject;
   
   if(dict) {
      while (arrayObject = [dictEnumerator nextObject]) {
      	//enumerate through the dictionay
         arrayEnumerator = [arrayObject objectEnumerator];
         while (idObject = [arrayEnumerator nextObject]) {
            //loop through the sub array and see if it contains this unique id
            if([idObject isEqualToString:unique]) {
               //this is what we are after
               return [[dict allKeysForObject:arrayObject] objectAtIndex:0];
            }
         }
      }
   }
   
   return nil;
}


- (void)dataSourceDictionaryArrayWithKey:(NSString *)key addString:(NSString *)string
{
   //add the string to the dataSourceDictionary
   [[dataSourceDictionary objectForKey:key] addObject:string];

   //add the object to the alphabeticDataSourceDictionary and sort it
   [[alphabeticDataSourceDictionary objectForKey:key] addObject:string];
   [[alphabeticDataSourceDictionary objectForKey:key] sortUsingSelector:@selector(caseInsensitiveCompare:)];

   [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDataSourceDictionaryChanged"
                                                       object:nil];
}

- (NSString *)dataSourceDictionaryArrayWithKey:(NSString *)key objectAtIndex:(int)index
{
   NSMutableArray *array = [dataSourceDictionary objectForKey:key];

   if(array) {
      if(index < [array count]) {
         return [array objectAtIndex:index];
      }
   }

   return nil; //no object for key or index is beyond bounds
}

- (NSString *)alphabeticDataSourceDictionaryArrayWithKey:(NSString *)key objectAtIndex:(int)index
{
   NSMutableArray *array = [alphabeticDataSourceDictionary objectForKey:key];
   
   if(array) {
      if(index < [array count]) {
         return [array objectAtIndex:index];
      }
   }

   return nil; //no object for key or index is beyond bounds
}

- (void)dataSourceDictionaryArrayWithKey:(NSString *)key removeString:(NSString *)string
{
   NSMutableArray *array = [dataSourceDictionary objectForKey:key];
   NSMutableArray *array2 = [alphabeticDataSourceDictionary objectForKey:key];

   if(array) {
      //remove this string so that it won't show up in the table
      [array removeObject:string];
      [array2 removeObject:string];
   }

   [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDataSourceDictionaryChanged"
                                                       object:nil];
}

- (int)dataSourceDictionaryIndexOfObject:(NSString *)object inArray:(NSString *)arrayName
{
   NSMutableArray *array = [dataSourceDictionary objectForKey:arrayName];
   if(array) {
      if([array containsObject:object]) {
         //return the index of object
         int index = [array indexOfObject:object];
         return index;
      }
   }

   return nil; //no array with arrayName or object not present in array
}

- (void)dataSourceDictionaryArrayWithKey:(NSString *)key moveObjectsAtIndexes:(NSArray *)movingIndexes toIndex:(int)index
{
   NSMutableArray *mainArray = [dataSourceDictionary objectForKey:key];
   NSMutableArray *movingArray = [NSMutableArray array];
   NSEnumerator *enumerator = [movingIndexes objectEnumerator];
   id anObject;

   if(mainArray) { //key is valid
      while (anObject = [enumerator nextObject]) {
         //loop through and build an array with all of the object we want to move
         if([anObject intValue] < index) {
            index--;
         }
         [movingArray addObject:[mainArray objectAtIndex:[anObject intValue]]];
      }
      //remove the dragged object
      [mainArray removeObjectsInArray:movingArray];
      //add the dragged objects at the new index
      [mainArray insertObjectsFromArray:movingArray atIndex:index];
   }
}

- (NSMutableArray *)filteredActorArray
{
   return filteredActorArray;
}

- (void)updateFilteredActorArray
{
   NSMutableArray *actorArray = [dataSourceDictionary objectForKey:@"actor"];

   [filteredActorArray release];
   filteredActorArray = [[NSMutableArray array] retain];
   
   if([[theDocument objectFilterController] isFiltering]) {
      //we are filtering 
      int i = 0;
      int j = 0;

      while([actorArray count] > i) {
         //loop through the actor array
         while([eventArray count] > j) {
            //see if there are any events with this actor which are visible
            SSEventObject *event = [eventArray objectAtIndex:j];
            if([[event actor] isEqualToString:[actorArray objectAtIndex:i]] && [event isVisible]) {
               //this actor row need to be displayed so add it and break
               [filteredActorArray addObject:[actorArray objectAtIndex:i]];
               break;
            }
            j++;
         }
         i++;
         j = 0;
      }
   } else {
      //not filtering so add all actors
      [filteredActorArray addObjectsFromArray:actorArray];
   }
}

- (int)numberOfUniqueSources
{
   return [[dataSourceDictionary objectForKey:@"source"] count];
}

- (int)numberOfUniqueActors
{
   return [[dataSourceDictionary objectForKey:@"actor"] count];
}

- (int)numberOfUniqueActions
{
   return [[dataSourceDictionary objectForKey:@"action"] count];
}

- (int)numberOfUniqueLocations
{
   return [[dataSourceDictionary objectForKey:@"location"] count];
}

- (int)numberOfUniqueObjects
{
   return [[dataSourceDictionary objectForKey:@"object"] count];
}

- (int)numberOfUniqueRemarks
{
   return [[dataSourceDictionary objectForKey:@"remark"] count];
}

- (int)numberOfActorsWithName:(NSString *)theName
{
   //return the number of actors with name
   return [[[aalosDictionary objectForKey:@"actor"] objectForKey:theName] count];
}

- (NSString *)title
{
   return [structureDictionary objectForKey:@"title"];
}

- (void)setTitle:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"title"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)author
{
   return [structureDictionary objectForKey:@"author"];
}

- (void)setAuthor:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"author"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSCalendarDate *)chartDate
{
   return [structureDictionary objectForKey:@"chartDate"];
}

- (void)setChartDate:(NSCalendarDate *)date
{
   if(date) {
      [structureDictionary setObject:date forKey:@"chartDate"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)whiteColorDesignation
{
   return [structureDictionary objectForKey:@"whiteColorDesignation"];
}

- (void)setWhiteColorDesignation:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"whiteColorDesignation"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)yellowColorDesignation
{
   return [structureDictionary objectForKey:@"yellowColorDesignation"];
}

- (void)setYellowColorDesignation:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"yellowColorDesignation"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)greenColorDesignation
{
   return [structureDictionary objectForKey:@"greenColorDesignation"];
}

- (void)setGreenColorDesignation:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"greenColorDesignation"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)lightBlueColorDesignation
{
   return [structureDictionary objectForKey:@"lightBlueColorDesignation"];
}

- (void)setLightBlueColorDesignation:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"lightBlueColorDesignation"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)blueColorDesignation
{
   return [structureDictionary objectForKey:@"blueColorDesignation"];
}

- (void)setBlueColorDesignation:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"blueColorDesignation"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)purpleColorDesignation
{
   return [structureDictionary objectForKey:@"purpleColorDesignation"];
}

- (void)setPurpleColorDesignation:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"purpleColorDesignation"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)orangeColorDesignation
{
   return [structureDictionary objectForKey:@"orangeColorDesignation"];
}

- (void)setOrangeColorDesignation:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"orangeColorDesignation"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)redColorDesignation
{
   return [structureDictionary objectForKey:@"redColorDesignation"];
}

- (void)setRedColorDesignation:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"redColorDesignation"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSMatrixPropertyChanged"
                                                          object:theDocument];
      
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondUDValue1
{
   return [structureDictionary objectForKey:@"diamondUDValue1"];
}

- (void)setDiamondUDValue1:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondUDValue1"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondUDValue2
{
   return [structureDictionary objectForKey:@"diamondUDValue2"];
}

- (void)setDiamondUDValue2:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondUDValue2"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondUDValue3
{
   return [structureDictionary objectForKey:@"diamondUDValue3"];
}

- (void)setDiamondUDValue3:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondUDValue3"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondUDValue4
{
   return [structureDictionary objectForKey:@"diamondUDValue4"];
}

- (void)setDiamondUDValue4:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondUDValue4"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondUDValue5
{
   return [structureDictionary objectForKey:@"diamondUDValue5"];
}

- (void)setDiamondUDValue5:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondUDValue5"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondUDValue6
{
   return [structureDictionary objectForKey:@"diamondUDValue6"];
}

- (void)setDiamondUDValue6:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondUDValue6"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondOptionUDValue1
{
   return [structureDictionary objectForKey:@"diamondOptionUDValue1"];
}

- (void)setDiamondOptionUDValue1:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondOptionUDValue1"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondOptionUDValue2
{
   return [structureDictionary objectForKey:@"diamondOptionUDValue2"];
}

- (void)setDiamondOptionUDValue2:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondOptionUDValue2"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondOptionUDValue3
{
   return [structureDictionary objectForKey:@"diamondOptionUDValue3"];
}

- (void)setDiamondOptionUDValue3:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondOptionUDValue3"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondOptionUDValue4
{
   return [structureDictionary objectForKey:@"diamondOptionUDValue4"];
}

- (void)setDiamondOptionUDValue4:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondOptionUDValue4"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondOptionUDValue5
{
   return [structureDictionary objectForKey:@"diamondOptionUDValue5"];
}

- (void)setDiamondOptionUDValue5:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondOptionUDValue5"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondTradeoffUDValue1
{
   return [structureDictionary objectForKey:@"diamondTradeoffUDValue1"];
}

- (void)setDiamondTradeoffUDValue1:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondTradeoffUDValue1"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondTradeoffUDValue2
{
   return [structureDictionary objectForKey:@"diamondTradeoffUDValue2"];
}

- (void)setDiamondTradeoffUDValue2:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondTradeoffUDValue2"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)diamondTradeoffUDValue3
{
   return [structureDictionary objectForKey:@"diamondTradeoffUDValue3"];
}

- (void)setDiamondTradeoffUDValue3:(NSString *)string
{
   if(string) {
      [structureDictionary setObject:string forKey:@"diamondTradeoffUDValue3"];
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondValuesChanged"
                                                          object:theDocument];

      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (NSString *)projectFolder
{
   return [structureDictionary objectForKey:@"projectFolder"];
}

- (void)setProjectFolder:(NSString *)path
{
   if(path) {
      [structureDictionary setObject:path forKey:@"projectFolder"];
      [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
   }
}

- (SSEventObject *)eventWithAddress:(NSString *)address
{
   //returns the event with address if an event with address doesn't exist returns nil
   NSEnumerator *enumerator = [[self eventArray] objectEnumerator];
   SSEventObject *anObject;

   while (anObject = [enumerator nextObject]) {
      if([[anObject address] isEqualToString:address]) {
         return anObject;
      }
   }

   return nil; //no event with name as its file name
}

- (SSEventObject *)eventWithUniqueId:(NSString *)theId
{
   //returns the event with id if an event with id doesn't exist returns nil
   NSEnumerator *enumerator = [[self eventArray] objectEnumerator];
   SSEventObject *anObject;

   while (anObject = [enumerator nextObject]) {
      if([[anObject unique_id] isEqualToString:theId]) {
         return anObject;
      }
   }

   return nil; //no event with id
}

- (SSCatalystComment *)commentWithUniqueId:(NSString *)theId
{
   //returns the comment with id if an comment with id doesn't exist returns nil
   NSEnumerator *enumerator = [[self commentArray] objectEnumerator];
   SSCatalystComment *anObject;
   
   while (anObject = [enumerator nextObject]) {
      if([[anObject unique_id] isEqualToString:theId]) {
         return anObject;
      }
   }
   
   return nil; //no comment with id
}


- (NSMutableArray *)allEventsContainingString:(NSString *)string
{
   NSMutableArray *theArray = [NSMutableArray array];
   NSArray *matchArray;
   int i = 0;
   
   //add matching actors
   [theArray addObjectsFromArray:[self allEventsWithActorContainingString:string]];
   
   //add the actions
   matchArray = [self allEventsWithActionContainingString:string];
   while(i < [matchArray count]) {
      if(![theArray containsObject:[matchArray objectAtIndex:i]]) {
         [theArray addObject:[matchArray objectAtIndex:i]]; 
      }
      i++;
   }
   
   //add the objects
   i = 0;
   matchArray = [self allEventsWithObjectContainingString:string];
   while(i < [matchArray count]) {
      if(![theArray containsObject:[matchArray objectAtIndex:i]]) {
         [theArray addObject:[matchArray objectAtIndex:i]]; 
      }
      i++;
   }
   
   //add the sources
   i = 0;
   matchArray = [self allEventsWithSourceContainingString:string];
   while(i < [matchArray count]) {
      if(![theArray containsObject:[matchArray objectAtIndex:i]]) {
         [theArray addObject:[matchArray objectAtIndex:i]]; 
      }
      i++;
   }
   
   //add the locations
   i = 0;
   matchArray = [self allEventsWithLocationContainingString:string];
   while(i < [matchArray count]) {
      if(![theArray containsObject:[matchArray objectAtIndex:i]]) {
         [theArray addObject:[matchArray objectAtIndex:i]]; 
      }
      i++;
   }
   
   //add the remarks
   i = 0;
   matchArray = [self allEventsWithRemarkContainingString:string];
   while(i < [matchArray count]) {
      if(![theArray containsObject:[matchArray objectAtIndex:i]]) {
         [theArray addObject:[matchArray objectAtIndex:i]]; 
      }
      i++;
   }
   
   return theArray;
}

- (NSMutableArray *)allEventsWithActorContainingString:(NSString *)string
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [eventArray count]) {
      SSEventObject *currentObject = [eventArray objectAtIndex:i];
      NSRange stringRange = [[currentObject actor] rangeOfString:string options:NSCaseInsensitiveSearch];
      if(stringRange.location != NSNotFound) {
         //add the event object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (NSMutableArray *)allEventsWithActionContainingString:(NSString *)string
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [eventArray count]) {
      SSEventObject *currentObject = [eventArray objectAtIndex:i];
      NSRange stringRange = [[currentObject action] rangeOfString:string options:NSCaseInsensitiveSearch];
      if(stringRange.location != NSNotFound) {
         //add the event object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}
- (NSMutableArray *)allEventsWithObjectContainingString:(NSString *)string
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [eventArray count]) {
      SSEventObject *currentObject = [eventArray objectAtIndex:i];
      NSRange stringRange = [[currentObject object] rangeOfString:string options:NSCaseInsensitiveSearch];
      if(stringRange.location != NSNotFound) {
         //add the event object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (NSMutableArray *)allEventsWithSourceContainingString:(NSString *)string
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [eventArray count]) {
      SSEventObject *currentObject = [eventArray objectAtIndex:i];
      NSRange stringRange = [[currentObject sourceString] rangeOfString:string options:NSCaseInsensitiveSearch];
      if(stringRange.location != NSNotFound) {
         //add the event object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (NSMutableArray *)allEventsWithLocationContainingString:(NSString *)string
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [eventArray count]) {
      SSEventObject *currentObject = [eventArray objectAtIndex:i];
      NSRange stringRange = [[currentObject location] rangeOfString:string options:NSCaseInsensitiveSearch];
      if(stringRange.location != NSNotFound) {
         //add the event object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (NSMutableArray *)allEventsWithRemarkContainingString:(NSString *)string
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [eventArray count]) {
      SSEventObject *currentObject = [eventArray objectAtIndex:i];
      NSRange stringRange = [[currentObject remark] rangeOfString:string options:NSCaseInsensitiveSearch];
      if(stringRange.location != NSNotFound) {
         //add the event object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (NSMutableArray *)allEventsWithBeginDate:(NSCalendarDate *)date
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [eventArray count]) {
      SSEventObject *currentObject = [eventArray objectAtIndex:i];
      if([[currentObject beginTime] dayOfCommonEra] == [date dayOfCommonEra]) {
         //add the event object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (NSMutableArray *)allEventsWithBeginTime:(NSCalendarDate *)date
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [eventArray count]) {
      SSEventObject *currentObject = [eventArray objectAtIndex:i];
      if([[currentObject beginTime] hourOfDay] == [date hourOfDay] &&
         [[currentObject beginTime] minuteOfHour] == [date minuteOfHour] &&
         [[currentObject beginTime] secondOfMinute] == [date secondOfMinute]) {
         //add the event object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (NSMutableArray *)allEventsWithEndDate:(NSCalendarDate *)date
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [eventArray count]) {
      SSEventObject *currentObject = [eventArray objectAtIndex:i];
      if([[currentObject endTime] dayOfCommonEra] == [date dayOfCommonEra]) {
         //add the event object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (NSMutableArray *)allEventsWithEndTime:(NSCalendarDate *)date
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [eventArray count]) {
      SSEventObject *currentObject = [eventArray objectAtIndex:i];
      if([[currentObject endTime] hourOfDay] == [date hourOfDay] &&
         [[currentObject endTime] minuteOfHour] == [date minuteOfHour] &&
         [[currentObject endTime] secondOfMinute] == [date secondOfMinute]) {
         //add the event object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (NSMutableArray *)allCommentsContainingString:(NSString *)string
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [commentArray count]) {
      SSCatalystComment *currentObject = [commentArray objectAtIndex:i];
      NSRange stringRange = [[currentObject commentString] rangeOfString:string options:NSCaseInsensitiveSearch];
      if(stringRange.location != NSNotFound) {
         //add the comment object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (NSMutableArray *)allDiamondsContainingString:(NSString *)string
{
   NSMutableArray *theArray = [NSMutableArray array];
   int i = 0;
   
   while(i < [needsDiamondArray count]) {
      SSNeedsDiamond *currentObject = [needsDiamondArray objectAtIndex:i];
      NSRange stringRange = [[currentObject searchString] rangeOfString:string options:NSCaseInsensitiveSearch];
      if(stringRange.location != NSNotFound) {
         //add the diamond object
         [theArray addObject:currentObject];
      }
      i++; 
   }
   
   return theArray;
}

- (void)validateEventBeginTime:(SSEventObject *)event
{
   //test to see if there is another event with this actor and begin time
   NSMutableArray *array = [[aalosDictionary objectForKey:@"actor"] objectForKey:[event actor]]; //get the array of events with this actor
   NSEnumerator *enumerator = [array objectEnumerator];
   id anObject;
   SSEventObject *otherEvent;
   NSComparisonResult result;
   int choice;
      
   while (anObject = [enumerator nextObject]) {
      if(![anObject isEqualToString:[event unique_id]]) {
         otherEvent = [self eventWithUniqueId:anObject];
         result = [[event beginTime] compare:[otherEvent beginTime]];

         if(result == NSOrderedSame) {
            //this event has the same beging time
            choice = NSRunAlertPanel(NSLocalizedString(@"Error", nil), [NSString stringWithFormat:@"%@ %@ - %@", NSLocalizedString(@"SameBeginTimes", nil), [event actor], [event action]], @"Continue", @"Change", nil, nil);

            if(choice != NSAlertDefaultReturn) {
               //user wants to edit
               [[SSEBDuplicateEditPanelController sharedEBDuplicateEditPanelController] showWindowForEvent:event];
            }
            
            break;
         }
      }
   }
}

- (void)validateNewEventBeginTime:(SSEventObject *)event
{
   //test to see if there is another event with this actor and begin time
   NSMutableArray *array = [[aalosDictionary objectForKey:@"actor"] objectForKey:[event actor]]; //get the array of events with this actor
   NSEnumerator *enumerator = [array objectEnumerator];
   id anObject;
   SSEventObject *otherEvent;
   NSComparisonResult result;
   int choice;

   if(!importCanceled) {
      while (anObject = [enumerator nextObject]) {
         if(![anObject isEqualToString:[event unique_id]]) {
            otherEvent = [self eventWithUniqueId:anObject];
            result = [[event beginTime] compare:[otherEvent beginTime]];

            if(result == NSOrderedSame) {
               //this event has the same beging time
               choice = [SSImportDuplicateAlertController displayImportDuplicateAlert:[NSString stringWithFormat:@"%@ (%@ - %@)", NSLocalizedString(@"SameBeginTimesInImport", nil), [event actor], [event action]]];

               switch(choice) {
                  case SSCancelImport:importCanceled = YES; //we set this here to stop further alerts.
                                                            //once the import is finished the document will act on this and tell us to remove all of the imported data
                     break;
                  case SSChangeImportedEB:[[SSEBDuplicateEditPanelController sharedEBDuplicateEditPanelController] showWindowForEvent:event];
                     break;
                  case SSSkipEBImport:[theDocument addSkippedEvent:event];
                     break;
                  default:
                     break;
               }
               break;
            }
         }
      }
   }
}

- (BOOL)importCanceled
{
   return importCanceled;
}

- (void)setImportCanceled:(BOOL)b
{
   importCanceled = b;
}

- (BOOL)eventExistsWithActorAndTime:(SSEventObject *)event
{
   //test to see if there is another event with this actor and begin time
   NSMutableArray *array = [[aalosDictionary objectForKey:@"actor"] objectForKey:[event actor]]; //get the array of events with this actor
   NSEnumerator *enumerator = [array objectEnumerator];
   id anObject;
   SSEventObject *otherEvent;
   NSComparisonResult result;

   while (anObject = [enumerator nextObject]) {
      if(![anObject isEqualToString:[event unique_id]]) {
         otherEvent = [self eventWithUniqueId:anObject];
         result = [[event beginTime] compare:[otherEvent beginTime]];

         if(result == NSOrderedSame) {
            //this event has the same beging time
            return YES;
         }
      }
   }

   return NO;
}

- (void)addCommentsFromArray:(NSMutableArray *)array
{
   NSEnumerator *enumerator = [array objectEnumerator];
   id anObject;

   while (anObject = [enumerator nextObject]) {
      [commentArray addObject:anObject];
      [[theDocument undoManager] registerUndoWithTarget:theDocument selector:@selector(deleteObject:) object:anObject]; //for undo
   }
}

- (void)addCommentToDocument:(SSCatalystComment *)comment structureDictionary:(NSMutableDictionary *)dict
{
   [[theDocument undoManager] registerUndoWithTarget:theDocument selector:@selector(deleteObject:) object:comment]; //for undo

   if(!dict) {
      dict = structureDictionary;
   }
   
   if([self commentWithUniqueId:[comment unique_id]]) {
      //there is already a comment with this ID change it
      [comment setUnique_id:[[SSChartDate calendarDate] descriptionWithCalendarFormat:@"%y%m%d%H%M%F"]];
   }
   
   [commentArray addObject:comment];
   [[dict objectForKey:@"comments"] addObject:comment];
   [theDocument addCommentToChartView:comment];

   [[NSNotificationCenter defaultCenter] postNotificationName:@"SSCommentDataChanged"
                                                       object:nil];

   [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
}

- (void)removeCommentFromDocument:(SSCatalystComment *)comment
{
   [[self commentArray] removeObjectIdenticalTo:comment];

   //remove the comment from structure dict
   NSMutableDictionary *dict = [self structureDictionaryForObject:comment];
   if(dict) {
      [[dict objectForKey:@"comments"] removeObjectIdenticalTo:comment];
   }

   [[NSNotificationCenter defaultCenter] postNotificationName:@"SSCommentDataChanged"
                                                       object:nil];

   [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
}

- (SSEventObject *)closestEventToComment:(SSCatalystComment *)comment
{
   //deturmins and returns the closest event to comment
   
   int i = 0;
   float distanceFromEvent; 
   float closestEventDistance = 1000000.0; //set it to a very high number so we can be sure that there is an event closer
   SSEventObject *closestEvent = nil;
   NSArray *sortedEvents = [[self eventArray] sortedArrayUsingSelector:@selector(compareByXPosition:)];

   NSPoint pt1 = NSMakePoint(([[comment commentView] frame].origin.x + ([[comment commentView] frame].size.width / 2) + .5),
                             ([[comment commentView] frame].origin.y + ([[comment commentView] frame].size.height) / 2) + .5); //set the center point fpr the comment
   NSPoint pt2;
   float ptxd;
   float ptyd;

   while(i < [sortedEvents count]) {
      pt2 = [[sortedEvents objectAtIndex:i] centerPoint];
      ptxd = pt1.x - pt2.x;
      ptyd = pt1.y - pt2.y;
      distanceFromEvent = sqrt( ptxd*ptxd + ptyd*ptyd ); //get this events distance from the comment

      if(distanceFromEvent < closestEventDistance) {
         //this event is closer so set it
         closestEventDistance = distanceFromEvent;
         closestEvent = [sortedEvents objectAtIndex:i];
      } else {
         if(pt2.x > pt1.x) {
            //the distance is getting greater and we have passed the comment on the x axis so there is no need to continue
            break;
         }
      }
      
      i++;
   }

   return closestEvent;
}

- (void)createGhostEventWithAddress:(NSString *)address  
{
   SSEventObject *ghostEvent = [[[SSEventObject alloc] initAsGhostEventWithAddress:address
                                                                             label:[NSNumber numberWithInt:SSWhiteLabelType]
                                                                         xPosition:0.0] autorelease];

   [self addEventToDocument:ghostEvent structureDictionary:nil];
}

//***********************************
- (void)addNeedsDiamondsFromArray:(NSMutableArray *)array
{
   NSEnumerator *enumerator = [array objectEnumerator];
   id anObject;

   while (anObject = [enumerator nextObject]) {
      [needsDiamondArray addObject:anObject];
      [[theDocument undoManager] registerUndoWithTarget:theDocument selector:@selector(deleteObject:) object:anObject]; //for undo
   }
   [self renumberNeedsDiamondsAboveIndex:0];
}

- (void)addNeedsDiamondToDocument:(SSNeedsDiamond *)diamond structureDictionary:(NSMutableDictionary *)dict
{
   if(!dict) {
      dict = structureDictionary;

   }

   [[dict objectForKey:@"needsDiamonds"] addObject:diamond];
   [needsDiamondArray addObject:diamond];
   [diamond setNumber:[NSNumber numberWithInt:[needsDiamondArray count]]];

   [theDocument redisplay];
   [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondDataChanged"
                                                       object:nil];

   [[theDocument undoManager] registerUndoWithTarget:theDocument selector:@selector(deleteObject:) object:diamond]; //for undo

   [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
}

- (void)removeNeedsDiamondFromDocument:(SSNeedsDiamond *)diamond
{
   NSMutableDictionary *structDict;
   int index = [needsDiamondArray indexOfObject:diamond];
   [needsDiamondArray removeObjectIdenticalTo:diamond]; //remove the diamond from the diamond array
   [self renumberNeedsDiamondsAboveIndex:index];

   if([[diamond owner] isKindOfClass:[SSEventObject class]]) {
      structDict = [self structureDictionaryForObject:[diamond owner]];
   } else {
      structDict = [self structureDictionaryForObject:[[diamond owner] linkedFrom]];
   }

   [[structDict objectForKey:@"needsDiamonds"] removeObjectIdenticalTo:diamond]; //remove the reference from the structureDictionary

   [[diamond owner] removeNeedsDiamond:diamond]; //remove the diamond from its owners diamond array

   [[NSNotificationCenter defaultCenter] postNotificationName:@"SSDiamondDataChanged"
                                                       object:nil];

   [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
}

- (void)renumberNeedsDiamondsAboveIndex:(int)index
{
   //renumber the needs diamonds
   int count = [needsDiamondArray count];
   int i;
   
   for (i = index; i < count; i++) {
      [[needsDiamondArray objectAtIndex:i] setNumber:[NSNumber numberWithInt:(i + 1)]]; 
   } 
}

- (void)setDefaultNeedsDiamondValuesDict:(NSMutableDictionary *)dict
{
   [defaultNeedsDiamondValues release];
   [dict retain];
   defaultNeedsDiamondValues = dict;
}

- (void)setDefaultNeedsDiamondValue:(NSString *)value forKey:(NSString *)key
{
   [defaultNeedsDiamondValues setObject:value forKey:key];
}

- (NSString *)defaultNeedsDiamondValueForKey:(NSString *)key
{
   return [defaultNeedsDiamondValues objectForKey:key];
}

//***********************************
- (NSMutableDictionary *)structureDictionaryForObject:(id)object
{
   NSString *key;
   
   if([object isKindOfClass:[SSEventObject class]]) {
      key = @"referencedEventBlocks";
    } else {
       key = @"comments";
    }

   return [self structureDictionaryForObject:object key:key dictionary:structureDictionary];
}

- (NSMutableDictionary *)structureDictionaryForObject:(id)object key:(NSString *)key dictionary:(NSMutableDictionary *)dict
{
   if([[dict objectForKey:key] containsObject:object]) {
      //it's in this dictionary
      return dict;
   }

   NSEnumerator *enumerator = [[dict objectForKey:@"subDirectories"] objectEnumerator];
   id anObject;
   NSMutableDictionary *subDict;
   
   while (anObject = [enumerator nextObject]) {
      subDict = [self structureDictionaryForObject:object key:key dictionary:anObject];

      if(subDict) {
         //we found it
         return subDict;
      }
   }

   return nil; //it's not on this branch
}

//***********************************converting links
- (void)convertAllLinksToConnectionObjects
{
   //when events are loaded from xml proper connection can't be made because the object donm't yet exist
   //this method is run once a chart loads and converts the information taken from the xml string into SSEventLinkObjects
   NSEnumerator *eventEnumerator = [[self eventArray] objectEnumerator];
   id eventObject;

   //loop through all of the events and change the link strings into SSEventLinkObjects
   while (eventObject = [eventEnumerator nextObject]) {
      NSEnumerator *linkEnumerator = [[eventObject linkArray] objectEnumerator];
      id linkDict;
      NSString *linkString;
      NSMutableArray *linksToReplaceArray = [NSMutableArray array];
      NSEnumerator *linksToReplaceEnumerator;
      id replaceDict;
      
      while (linkDict = [linkEnumerator nextObject]) {
         linkString = [linkDict objectForKey:@"link"];
         SSEventObject *linkedToEvent = [self eventWithAddress:linkString];

         if(!linkedToEvent) {
            //there was no object with that file name. create a ghost event
            [self createGhostEventWithAddress:linkString];
            linkedToEvent = [self eventWithAddress:linkString];
         }

         SSEventLinkObject *linkObject = [[[SSEventLinkObject alloc] initWithLinkedFrom:eventObject
                                                                         linkedTo:linkedToEvent
                                                                             type:[linkDict objectForKey:@"type"]] autorelease];         
         [linksToReplaceArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:linkObject, @"object", linkString, @"name", nil, nil]];
      }

      linksToReplaceEnumerator = [linksToReplaceArray objectEnumerator];
      while (replaceDict = [linksToReplaceEnumerator nextObject]) {
         [eventObject replaceLinkWithName:[replaceDict objectForKey:@"name"] withEventLinkObject:[replaceDict objectForKey:@"object"]];
      }
   }
}

- (void)convertLinksForEventsInDictionary:(NSMutableDictionary *)structDict appendToFrontOfLink:(NSString *)appentToFront
{
   //when events are loaded from xml proper connection can't be made because the object don't yet exist
   //this method is run once a file has been imported and converts the information taken from the xml string into SSEventLinkObjects
   NSEnumerator *eventEnumerator = [[self allEventsInStructure:structDict] objectEnumerator];
   id eventObject;

   //loop through all of the events and change the link strings into SSEventLinkObjects
   while (eventObject = [eventEnumerator nextObject]) {
      NSEnumerator *linkEnumerator = [[eventObject linkArray] objectEnumerator];
      id linkDict;
      NSString *linkString;
      NSMutableArray *linksToReplaceArray = [NSMutableArray array];
      NSEnumerator *linksToReplaceEnumerator;
      id replaceDict;

      while (linkDict = [linkEnumerator nextObject]) {
         linkString = [NSString stringWithFormat:@"%@%@", appentToFront, [linkDict objectForKey:@"link"]];
         SSEventObject *linkedToEvent = [self eventWithAddress:linkString];

         if(!linkedToEvent) {
            //there was no object with that file name. create a ghost event
            [self createGhostEventWithAddress:linkString];
            linkedToEvent = [self eventWithAddress:linkString];
         }

         SSEventLinkObject *linkObject = [[[SSEventLinkObject alloc] initWithLinkedFrom:eventObject
                                                                               linkedTo:linkedToEvent
                                                                                   type:[linkDict objectForKey:@"type"]] autorelease];
         [linksToReplaceArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:linkObject, @"object", [linkDict objectForKey:@"link"], @"name", nil, nil]];
      }

      linksToReplaceEnumerator = [linksToReplaceArray objectEnumerator];
      while (replaceDict = [linksToReplaceEnumerator nextObject]) {
         [eventObject replaceLinkWithName:[replaceDict objectForKey:@"name"] withEventLinkObject:[replaceDict objectForKey:@"object"]];
      }
   }
}

- (void)convertLinksForEvent:(SSEventObject *)eventObject
{
   NSEnumerator *linkEnumerator = [[eventObject linkArray] objectEnumerator];
   id linkDict;
   NSString *linkString;
   NSMutableArray *linksToReplaceArray = [NSMutableArray array];
   NSEnumerator *linksToReplaceEnumerator;
   id replaceDict;

   while (linkDict = [linkEnumerator nextObject]) {
      linkString = [linkDict objectForKey:@"link"];
      SSEventObject *linkedToEvent = [self eventWithAddress:linkString];

      if(!linkedToEvent) {
         //there was no object with that file name. create a ghost event
         [self createGhostEventWithAddress:linkString];
         linkedToEvent = [self eventWithAddress:linkString];
      }

      SSEventLinkObject *linkObject = [[[SSEventLinkObject alloc] initWithLinkedFrom:eventObject
                                                                            linkedTo:linkedToEvent
                                                                                type:[linkDict objectForKey:@"type"]] autorelease];
      [linksToReplaceArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:linkObject, @"object", linkString, @"name", nil, nil]];
   }

   linksToReplaceEnumerator = [linksToReplaceArray objectEnumerator];
   while (replaceDict = [linksToReplaceEnumerator nextObject]) {
      [eventObject replaceLinkWithName:[replaceDict objectForKey:@"name"] withEventLinkObject:[replaceDict objectForKey:@"object"]];
   }
   
}

- (void)setEventLabelsAndPositions:(NSMutableArray *)referenceDict
{
   //sets the event lable and position run after document loads
   NSEnumerator *enumerator = [referenceDict objectEnumerator];
   id eventDict;
   SSEventObject *event;

   while (eventDict = [enumerator nextObject]) {
      if([eventDict isKindOfClass:[NSMutableDictionary class]]) { //just make sure that we are dealing with a dictionary
         event = [self eventWithAddress:[eventDict objectForKey:@"address"]];
         [event setXPosition:[[eventDict objectForKey:@"xPosition"] floatValue]];
         [event setLabel:[eventDict objectForKey:@"label"]];
      }
   }
}

- (void)convertAllDiamondOwners
{
   NSEnumerator *enumerator = [[self needsDiamondArray] objectEnumerator];
   id anObject;

   while (anObject = [enumerator nextObject]) {
      [self convertOwnerForDiamond:anObject appendToFrontOfOwnerAddress:[NSString string]];
   }
}

- (void)convertAllDiamondOwnersInDictionary:(NSMutableDictionary *)dict appendToFrontOfOwnerAddress:(NSString *)append
{
   NSEnumerator *enumerator = [[self allNeedsDiamondsInStructure:dict] objectEnumerator];
   id anObject;

   while (anObject = [enumerator nextObject]) {
      [self convertOwnerForDiamond:anObject appendToFrontOfOwnerAddress:append];
   }
}

- (void)convertOwnerForDiamond:(SSNeedsDiamond *)diamond appendToFrontOfOwnerAddress:(NSString *)append
{
   //when loaded from an xml file the diamonds owner is an address string so we need to convert that to an object
   if([[diamond owner] rangeOfString:@"--(link)--"].location != NSNotFound) {
      //it could be a link
      NSArray *eventAddresses = [[diamond owner] componentsSeparatedByString:@"--(link)--"];
      if([[eventAddresses objectAtIndex:0] hasSuffix:@".xml"] && [[eventAddresses objectAtIndex:1] hasSuffix:@".xml"]) {
         //after the split both strings ended with .xml so it must be a link
         SSEventObject *fromObject = [self eventWithAddress:[append stringByAppendingString:[eventAddresses objectAtIndex:0]]];
         SSEventObject *toObject = [self eventWithAddress:[append stringByAppendingString:[eventAddresses objectAtIndex:1]]];
         SSEventLinkObject *diamondOwner = [fromObject linkObjectConnectingEvent:toObject];
         [diamondOwner addNeedsDiamond:diamond];
         [diamond setOwner:diamondOwner];
         return;
      }
   }

   //it got this far so we are going to try and add it to an EB
   SSEventObject *diamondOwner = [self eventWithAddress:[append stringByAppendingString:[diamond owner]]];
   [diamondOwner addNeedsDiamond:diamond];
   [diamond setOwner:diamondOwner];
}

- (void)convertAllCommentClosestEvents
{
   NSEnumerator *enumerator = [[self commentArray] objectEnumerator];
   id anObject;

   while (anObject = [enumerator nextObject]) {
      [self convertClosestEventForComment:anObject];
   }
}

- (void)convertAllCommentClosestEventsInDictionary:(NSMutableDictionary *)dict
{
   NSEnumerator *enumerator = [[self allCommentsInStructure:dict] objectEnumerator];
   id anObject;

   while (anObject = [enumerator nextObject]) {
      [self convertClosestEventForComment:anObject];
   }
}

- (void)convertClosestEventForComment:(SSCatalystComment *)comment
{
   //when loaded from an xml file the comments closest event is a unique id string so we need to convert that to an object
   [comment setClosestEvent:[self eventWithUniqueId:[comment closestEvent]]];
   [comment followClosestEvent];
}

- (void)setAalosDictionary:(NSMutableDictionary *)dict
{
   [aalosDictionary release];
   [dict retain];
   aalosDictionary = dict;
}

- (void)setDataSourceDictionary:(NSMutableDictionary *)dict
{
   [dataSourceDictionary release];
   [dict retain];
   dataSourceDictionary = dict;
}

- (void)setAlphabeticDataSourceDictionary:(NSMutableDictionary *)dict
{
   [alphabeticDataSourceDictionary release];
   [dict retain];
   alphabeticDataSourceDictionary = dict;
}

- (void)setStructureDictionary:(NSMutableDictionary *)dict
{
   [structureDictionary release];
   [dict retain];
   structureDictionary = dict;
}

- (void)setEventArray:(NSMutableArray *)array
{
   [eventArray release];
   [array retain];
   eventArray = array;
}

- (void)setCommentArray:(NSMutableArray *)array
{
   [commentArray release];
   [array retain];
   commentArray = array;
}

- (void)setNeedsDiamondArray:(NSMutableArray *)array
{
   [needsDiamondArray release];
   [array retain];
   needsDiamondArray = array;
}

- (void)setTheDocument:(id)doc
{
   theDocument = doc;
}

- (void)setActorColumnWidth:(float)num
{
   actorColumnWidth = num;
}

- (float)actorColumnWidth
{
   return actorColumnWidth;
}

- (int)displayMode
{
   return displayMode;
}

- (void)setDisplayMode:(int)mode
{
   displayMode = mode;
}

- (float)overlapUnit
{
   return overlapUnit;
}

- (void)setOverlapUnit:(float)unit
{
   overlapUnit = unit;
}

- (float)overlapPixelsPerUnit
{
   return overlapPixelsPerUnit;
}

- (void)setOverlapPixelsPerUnit:(float)pix
{
   overlapPixelsPerUnit = pix;
}

//***********************************
- (NSMutableArray *)poisonWordArray
{
   return [structureDictionary objectForKey:@"poisonWords"];   
}

- (void)addPoisonWord:(SSPoisonWord *)word
{
   if(word) {
      [[structureDictionary objectForKey:@"poisonWords"] addObject:word];
      [[theDocument undoManager] registerUndoWithTarget:theDocument selector:@selector(removePoisonWord:) object:word]; //for undo

      [[NSNotificationCenter defaultCenter] postNotificationName:@"SSPoisonWordsChanged"
                                                          object:nil];
   }
}

- (void)removePoisonWord:(SSPoisonWord *)word
{
   [[structureDictionary objectForKey:@"poisonWords"] removeObjectIdenticalTo:word];
   [[theDocument undoManager] registerUndoWithTarget:theDocument selector:@selector(addPoisonWord:) object:word]; //for undo

   [[NSNotificationCenter defaultCenter] postNotificationName:@"SSPoisonWordsChanged"
                                                       object:nil];
}

//***********************************
- (NSData *)glossaryDataForType:(NSString *)type
{
   //used for EB glossaries
   NSMutableArray *glossaryArray = [alphabeticDataSourceDictionary objectForKey:type];
   NSString *glossaryString = [NSString string];
   NSEnumerator *enumerator;
   id anObject;

   if(glossaryArray) { //there is an entry for type so lets build the data object
      enumerator = [glossaryArray objectEnumerator];
      while (anObject = [enumerator nextObject]) {
         //add this string to the glossaryString
         if(![anObject isEqualToString:[NSString string]]) { //if it is an empty string dont include it
            glossaryString = [glossaryString stringByAppendingString:[NSString stringWithFormat:@"%@\n", anObject]];
         }
      }
      return [glossaryString dataUsingEncoding:NSUTF8StringEncoding
                          allowLossyConversion:YES];
   }   
   
   return [NSData data];
}

- (NSData *)optionGlossaryData
{
   NSString *glossaryString = [NSString string];
   NSEnumerator *diamondEnumerator = [needsDiamondArray objectEnumerator];
   NSEnumerator *optionEnumerator;
   id diamondObject;
   id optionObject;

   while (diamondObject = [diamondEnumerator nextObject]) {
      //enumerate this diamonds options
      optionEnumerator = [[diamondObject optionArray] objectEnumerator];
      while (optionObject = [optionEnumerator nextObject]) {
         if(![[optionObject option] isEqualToString:[NSString string]]) { //if it is an empty string dont include it
            glossaryString = [glossaryString stringByAppendingString:[NSString stringWithFormat:@"%@\n", [optionObject option]]];
         }
      }
   }
   
   return [glossaryString dataUsingEncoding:NSUTF8StringEncoding
                       allowLossyConversion:YES];
}

- (NSData *)proTradeoffGlossaryData
{
   NSString *glossaryString = [NSString string];
   NSEnumerator *diamondEnumerator = [needsDiamondArray objectEnumerator];
   NSEnumerator *optionEnumerator;
   NSEnumerator *tradeoffEnumerator;
   id diamondObject;
   id optionObject;
   id tradeoffObject;

   while (diamondObject = [diamondEnumerator nextObject]) {
      //enumerate this diamonds options
      optionEnumerator = [[diamondObject optionArray] objectEnumerator];
      while (optionObject = [optionEnumerator nextObject]) {
         //enumerate this options tradeoffs
         tradeoffEnumerator = [[optionObject tradeoffArray] objectEnumerator];
         while (tradeoffObject = [tradeoffEnumerator nextObject]) {
            if(![[tradeoffObject pro] isEqualToString:[NSString string]]) { //if it is an empty string dont include it
               glossaryString = [glossaryString stringByAppendingString:[NSString stringWithFormat:@"%@\n", [tradeoffObject pro]]];
            }
         }
      }
   }

   return [glossaryString dataUsingEncoding:NSUTF8StringEncoding
                       allowLossyConversion:YES];
}

- (NSData *)conTradeoffGlossaryData
{
   NSString *glossaryString = [NSString string];
   NSEnumerator *diamondEnumerator = [needsDiamondArray objectEnumerator];
   NSEnumerator *optionEnumerator;
   NSEnumerator *tradeoffEnumerator;
   id diamondObject;
   id optionObject;
   id tradeoffObject;

   while (diamondObject = [diamondEnumerator nextObject]) {
      //enumerate this diamonds options
      optionEnumerator = [[diamondObject optionArray] objectEnumerator];
      while (optionObject = [optionEnumerator nextObject]) {
         //enumerate this options tradeoffs
         tradeoffEnumerator = [[optionObject tradeoffArray] objectEnumerator];
         while (tradeoffObject = [tradeoffEnumerator nextObject]) {
            if(![[tradeoffObject con] isEqualToString:[NSString string]]) { //if it is an empty string dont include it
               glossaryString = [glossaryString stringByAppendingString:[NSString stringWithFormat:@"%@\n", [tradeoffObject con]]];
            }
         }
      }
   }

   return [glossaryString dataUsingEncoding:NSUTF8StringEncoding
                       allowLossyConversion:YES];
}

- (NSData *)remarkListData
{
   NSString *dataString = [NSString string];
   NSEnumerator *enumerator = [[[self eventArray] sortedArrayUsingSelector:@selector(compareByRemark:)] objectEnumerator];
   id anObject;
   
   while (anObject = [enumerator nextObject]) {
      //add this EB to the to the dataString if it has a remark
      if(![[anObject remark] isEqualToString:[NSString string]]) { //if it is an empty string dont include it
         dataString = [dataString stringByAppendingString:[NSString stringWithFormat:@"%@ [%@ - %@]\n",
            [(SSEventObject *)anObject remark], [(SSEventObject *)anObject actor], [(SSEventObject *)anObject action]]];
      }
   }

   return [dataString dataUsingEncoding:NSUTF8StringEncoding
                       allowLossyConversion:YES];
}

- (NSData *)eventListData
{
   NSString *dataString = [NSString string];
   NSEnumerator *enumerator = [[[self eventArray] sortedArrayUsingSelector:@selector(compareByBeginTime:)] objectEnumerator];
   SSEventObject *anObject;

   while (anObject = [enumerator nextObject]) {
      //add this EB to the to the dataString
      dataString = [dataString stringByAppendingString:[NSString stringWithFormat:@"At %@, %@ %@ %@ at %@\n",
         [[anObject beginTime] descriptionWithCalendarFormat:@"%Y:%m:%d %H:%M:%S:%F"], [[anObject actor] capitalizedString], [anObject action], [anObject object], [anObject location]]];
   }

   return [dataString dataUsingEncoding:NSUTF8StringEncoding
                   allowLossyConversion:YES];
}

- (NSData *)commentListData
{
   NSString *dataString = [NSString string];
   NSEnumerator *enumerator = [[self commentArray] objectEnumerator];
   SSCatalystComment *anObject;

   while (anObject = [enumerator nextObject]) {
      //add this comment to the to the dataString
      dataString = [dataString stringByAppendingString:[NSString stringWithFormat:@"%@ \t%@\n",
          [anObject commentString], [anObject typeString]]];
   }

   return [dataString dataUsingEncoding:NSUTF8StringEncoding
                   allowLossyConversion:YES];
}

- (NSData *)diamondListData
{
   NSString *dataString = [NSString string];
   NSEnumerator *diamondEnumerator = [[self needsDiamondArray] objectEnumerator];
   SSNeedsDiamond *diamondObject;
   NSEnumerator *optionEnumerator;
   SSDiamondOption *optionObject;
   NSEnumerator *tradeoffEnumerator;
   SSDiamondTradeoff *tradeoffObject;

   //create the column titles
   dataString = [dataString stringByAppendingString:[NSString stringWithFormat:@"Diamond No.,State,Type,Origin,Analyst,Description,%@,%@,%@,%@,%@,%@,Options,Option,%@,%@,%@,%@,%@,Tradeoffs,Pro,%@,%@,Con,%@,\n",
      [self structureObjectForKey:@"diamondUDValue1"], [self structureObjectForKey:@"diamondUDValue2"], [self structureObjectForKey:@"diamondUDValue3"],
      [self structureObjectForKey:@"diamondUDValue4"], [self structureObjectForKey:@"diamondUDValue5"], [self structureObjectForKey:@"diamondUDValue6"],
      [self structureObjectForKey:@"diamondOptionUDValue1"], [self structureObjectForKey:@"diamondOptionUDValue2"], [self structureObjectForKey:@"diamondOptionUDValue3"],
      [self structureObjectForKey:@"diamondOptionUDValue4"], [self structureObjectForKey:@"diamondOptionUDValue5"],
      [self structureObjectForKey:@"diamondTradeoffUDValue1"], [self structureObjectForKey:@"diamondTradeoffUDValue2"], [self structureObjectForKey:@"diamondTradeoffUDValue3"]]];

   while (diamondObject = [diamondEnumerator nextObject]) {
      //add this diamond to the to the dataString
      dataString = [dataString stringByAppendingString:[NSString stringWithFormat:@"%@,%@,%@,%@,%@,%@,%@,%@,%@,%@,%@,%@,,,,,,,,,,,,,,\n",
         [diamondObject number], [diamondObject diamondStateString], [diamondObject ownerType], [diamondObject ownerDescriptionForCSV],
         [diamondObject analyst], [diamondObject description], [diamondObject udValue1], [diamondObject udValue2], [diamondObject udValue3],
         [diamondObject udValue4], [diamondObject udValue5], [diamondObject udValue6]]];

      //enumerate this diamonds options
      optionEnumerator = [[diamondObject optionArray] objectEnumerator];
      while (optionObject = [optionEnumerator nextObject]) {
         //add this option to the dataString
         dataString = [dataString stringByAppendingString:[NSString stringWithFormat:@",,,,,,,,,,,,%d,%@,%@,%@,%@,%@,%@,,,,,,,\n",
            ([[diamondObject optionArray] indexOfObject:optionObject] + 1),  [optionObject option], [optionObject udValue1], [optionObject udValue2],
            [optionObject udValue3], [optionObject udValue4], [optionObject udValue5]]];

         //enumerate through the tradeoffs
         tradeoffEnumerator = [[optionObject tradeoffArray] objectEnumerator];
         while (tradeoffObject = [tradeoffEnumerator nextObject]) {
            //add this tradeoff to the dataString
            dataString = [dataString stringByAppendingString:[NSString stringWithFormat:@",,,,,,,,,,,,,,,,,,,%d,%@,%@,%@,%@,%@,\n",
               ([[optionObject tradeoffArray] indexOfObject:tradeoffObject] + 1),  [tradeoffObject pro], [tradeoffObject udValue1], [tradeoffObject udValue2],
               [tradeoffObject con], [tradeoffObject udValue3]]];

         }
      }
   }

   return [dataString dataUsingEncoding:NSUTF8StringEncoding
                   allowLossyConversion:YES];
}

//***********************************
- (SSEventObject *)currentLinkFromEvent
{
   return currentLinkFromEvent;
}

- (void)setCurrentLinkFromEvent:(SSEventObject *)event
{
   currentLinkFromEvent = event;
}


//***********************************

- (void)registerForAllEventNotifications
{
   //after loading a compressed file we need to register for notifications from the event objects
   NSEnumerator *enumerator = [[self eventArray] objectEnumerator];
   id anObject;
   NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
   
   while (anObject = [enumerator nextObject]) {
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeActorEntry:)
                 name:@"SSActorChanged"
               object:anObject];
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeActionEntry:)
                 name:@"SSActionChanged"
               object:anObject];
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeLocationEntry:)
                 name:@"SSLocationChanged"
               object:anObject];
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeSourceEntry:)
                 name:@"SSSourceChanged"
               object:anObject];
      [nc addObserver:self
             selector:@selector(aalosDictionaryChangeObjectEntry:)
                 name:@"SSObjectChanged"
               object:anObject];
   }
}
//***********************************coding
- (void)encodeWithCoder:(NSCoder *)coder
{
   [self setActorColumnWidth:[theDocument actorColumnWidth]]; //update the width
   [self setDisplayMode:[theDocument displayMode]];
   [self setOverlapUnit:[theDocument overlapUnit]];
   [self setOverlapPixelsPerUnit:[theDocument overlapPixelsPerUnit]];

   [coder encodeObject:aalosDictionary forKey:@"aalosDictionary"];
   [coder encodeObject:dataSourceDictionary forKey:@"dataSourceDictionary"];
   [coder encodeObject:alphabeticDataSourceDictionary forKey:@"alphabeticDataSourceDictionary"];
   [coder encodeObject:structureDictionary forKey:@"structureDictionary"];
   [coder encodeObject:commentArray forKey:@"commentArray"];
   [coder encodeObject:eventArray forKey:@"eventArray"];
   [coder encodeObject:needsDiamondArray forKey:@"needsDiamondArray"];
   [coder encodeObject:defaultNeedsDiamondValues forKey:@"defaultNeedsDiamondValues"];
   [coder encodeFloat:actorColumnWidth forKey:@"actorColumnWidth"];
   [coder encodeInt:displayMode forKey:@"displayMode"];
   [coder encodeFloat:overlapUnit forKey:@"overlapUnit"];
   [coder encodeFloat:overlapPixelsPerUnit forKey:@"overlapPixelsPerUnitFloat"];
}

- (id)initWithCoder:(NSCoder *)coder
{
   if(self = [super init]) {
      actorColumnWidth = 0.0;

      [self setAalosDictionary:[coder decodeObjectForKey:@"aalosDictionary"]];
      [self setDataSourceDictionary:[coder decodeObjectForKey:@"dataSourceDictionary"]];
      [self setCommentArray:[coder decodeObjectForKey:@"commentArray"]];
      [self setEventArray:[coder decodeObjectForKey:@"eventArray"]];

      if([coder containsValueForKey:@"alphabeticDataSourceDictionary"]) {
         [self setAlphabeticDataSourceDictionary:[coder decodeObjectForKey:@"alphabeticDataSourceDictionary"]];
      } else {
         //this file was saved before we added alphabeticDataSourceDictionary
         NSMutableDictionary *dict = [NSMutableDictionary dictionary];
         NSMutableArray *actionArray = [[[NSMutableArray alloc] initWithArray:[dataSourceDictionary objectForKey:@"action"] copyItems:YES] autorelease];
         NSMutableArray *actorArray = [[[NSMutableArray alloc] initWithArray:[dataSourceDictionary objectForKey:@"actor"] copyItems:YES] autorelease];
         NSMutableArray *locationArray = [[[NSMutableArray alloc] initWithArray:[dataSourceDictionary objectForKey:@"location"] copyItems:YES] autorelease];
         NSMutableArray *sourceArray = [[[NSMutableArray alloc] initWithArray:[dataSourceDictionary objectForKey:@"source"] copyItems:YES] autorelease];
         NSMutableArray *objectArray = [[[NSMutableArray alloc] initWithArray:[dataSourceDictionary objectForKey:@"object"] copyItems:YES] autorelease];
         NSMutableArray *remarkArray = [[[NSMutableArray alloc] initWithArray:[dataSourceDictionary objectForKey:@"remark"] copyItems:YES] autorelease];
         [dict setObject:actionArray forKey:@"action"];
         [dict setObject:actorArray forKey:@"actor"];
         [dict setObject:locationArray forKey:@"location"];
         [dict setObject:sourceArray forKey:@"source"];
         [dict setObject:objectArray forKey:@"object"];
         [dict setObject:remarkArray forKey:@"remark"];
         [[dict objectForKey:@"actor"] sortUsingSelector:@selector(caseInsensitiveCompare:)];
         [[dict objectForKey:@"action"] sortUsingSelector:@selector(caseInsensitiveCompare:)];
         [[dict objectForKey:@"object"] sortUsingSelector:@selector(caseInsensitiveCompare:)];
         [[dict objectForKey:@"location"] sortUsingSelector:@selector(caseInsensitiveCompare:)];
         [[dict objectForKey:@"source"] sortUsingSelector:@selector(caseInsensitiveCompare:)];
         [[dict objectForKey:@"remark"] sortUsingSelector:@selector(caseInsensitiveCompare:)];
         [self setAlphabeticDataSourceDictionary:dict];
      }

      if([coder containsValueForKey:@"structureDictionary"]) {
         [self setStructureDictionary:[coder decodeObjectForKey:@"structureDictionary"]];
      } else {
         //this file was saved before we added structureDictionary
         NSString *userName = NSUserName();
         NSMutableDictionary *structDict = [NSMutableDictionary dictionary];
         [structDict setObject:[NSString string] forKey:@"fileName"];
         [structDict setObject:[[SSChartDate calendarDate] descriptionWithCalendarFormat:@"%y%m%d%H%M%F"] forKey:@"unique_id"];
         [structDict setObject:userName forKey:@"name"];
         [structDict setObject:[NSString string] forKey:@"author"];
         [structDict setObject:[[[NSMutableArray alloc] initWithArray:[self eventArray] copyItems:NO] autorelease] forKey:@"referencedEventBlocks"];
         [structDict setObject:[[[NSMutableArray alloc] initWithArray:[self commentArray] copyItems:NO] autorelease] forKey:@"comments"];
         [structDict setObject:[NSMutableArray array] forKey:@"needsDiamonds"];
         [structDict setObject:[NSMutableArray array] forKey:@"subDirectories"];
         [self setStructureDictionary:structDict];

         //the event blocks wont have addresses either so set them
         NSEnumerator *enumerator = [[self eventArray] objectEnumerator];
         id anObject;

         while (anObject = [enumerator nextObject]) {
            [anObject setAddress:[self addressForNewEvent]];
         }
      }

      //if the structureDictionary dosn't have a needs diamond array set one
      if(![structureDictionary objectForKey:@"needsDiamonds"]) {
         [structureDictionary setObject:[NSMutableArray array] forKey:@"needsDiamonds"];

         NSEnumerator *enumerator = [[structureDictionary objectForKey:@"needsDiamonds"] objectEnumerator];
         id anObject;

         while (anObject = [enumerator nextObject]) {
            [anObject setObject:[NSMutableArray array] forKey:@"needsDiamonds"];
         }
      }

      if([coder containsValueForKey:@"needsDiamondArray"]) {
         [self setNeedsDiamondArray:[coder decodeObjectForKey:@"needsDiamondArray"]];
      } else {
         //this file was saved before we added the needsDiamondArray
         needsDiamondArray = [[NSMutableArray alloc] init];
      }

      if([coder containsValueForKey:@"actorColumnWidth"]) {
         [self setActorColumnWidth:[coder decodeFloatForKey:@"actorColumnWidth"]];
      }

      //we changed the value name to title and added color info on 22/4/03 so test for it
      if([structureDictionary objectForKey:@"name"]) {
         //it needs to be updated
         NSString *titleString = [[structureDictionary objectForKey:@"name"] retain];
         [structureDictionary removeObjectForKey:@"name"];
         [structureDictionary setObject:titleString forKey:@"title"];
         [titleString release];

         [structureDictionary setObject:[NSCalendarDate calendarDate] forKey:@"chartDate"];
         [structureDictionary setObject:@"Standard EB" forKey:@"whiteColorDesignation"];
         [structureDictionary setObject:@"Not used" forKey:@"yellowColorDesignation"];
         [structureDictionary setObject:@"Not used" forKey:@"greenColorDesignation"];
         [structureDictionary setObject:@"Not used" forKey:@"lightBlueColorDesignation"];
         [structureDictionary setObject:@"Not used" forKey:@"blueColorDesignation"];
         [structureDictionary setObject:@"Not used" forKey:@"purpleColorDesignation"];
         [structureDictionary setObject:@"Not used" forKey:@"orangeColorDesignation"];
         [structureDictionary setObject:@"Not used" forKey:@"redColorDesignation"];
      }

      if(![structureDictionary objectForKey:@"diamondUDValue1"]) {
         //we added default diamond lables on october 2 2003 and this file was saved before that
         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue1Key] forKey:@"diamondUDValue1"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue2Key] forKey:@"diamondUDValue2"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue3Key] forKey:@"diamondUDValue3"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue4Key] forKey:@"diamondUDValue4"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue5Key] forKey:@"diamondUDValue5"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondUDValue6Key] forKey:@"diamondUDValue6"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondOptionUDValue1Key] forKey:@"diamondOptionUDValue1"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondOptionUDValue2Key] forKey:@"diamondOptionUDValue2"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondOptionUDValue3Key] forKey:@"diamondOptionUDValue3"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondOptionUDValue4Key] forKey:@"diamondOptionUDValue4"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondOptionUDValue5Key] forKey:@"diamondOptionUDValue5"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondTradeoffUDValue1Key] forKey:@"diamondTradeoffUDValue1"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondTradeoffUDValue2Key] forKey:@"diamondTradeoffUDValue2"];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultDiamondTradeoffUDValue3Key] forKey:@"diamondTradeoffUDValue3"];
      }

      if(![structureDictionary objectForKey:@"projectFolder"]) {
         //we added project folder on 24/11/2003
         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
         [structureDictionary setObject:[defaults stringForKey:SSDefaultProjectFolderKey] forKey:@"projectFolder"];
      }

      if([coder containsValueForKey:@"defaultNeedsDiamondValues"]) {
         [self setDefaultNeedsDiamondValuesDict:[coder decodeObjectForKey:@"defaultNeedsDiamondValues"]];
      } else {
         //this file was saved before we added the defaultNeedsDiamondValues was added
         defaultNeedsDiamondValues = [[NSMutableDictionary alloc] init];
         [defaultNeedsDiamondValues setObject:[NSString string] forKey:@"analyst"];
         [defaultNeedsDiamondValues setObject:[NSString string] forKey:@"fileID"];
      }

      if([coder containsValueForKey:@"displayMode"]) {
         [self setDisplayMode:[coder decodeIntForKey:@"displayMode"]];
      }

      if([coder containsValueForKey:@"overlapUnit"]) {
         [self setOverlapUnit:[coder decodeFloatForKey:@"overlapUnit"]];
      }

      if([coder containsValueForKey:@"overlapPixelsPerUnitFloat"]) {
         [self setOverlapPixelsPerUnit:[coder decodeFloatForKey:@"overlapPixelsPerUnitFloat"]];
      } else if([coder containsValueForKey:@"overlapPixelsPerUnit"]) {
         [self setOverlapPixelsPerUnit:[coder decodeIntForKey:@"overlapPixelsPerUnit"]];
      }

      if(![structureDictionary objectForKey:@"poisonWords"]) {
         //saved before poisond words were added
         [structureDictionary setObject:[NSMutableArray array] forKey:@"poisonWords"];
         //add the standard poison words
         [self addPoisonWord:[[[SSPoisonWord alloc] initWithPoisonWord:NSLocalizedString(@"Was", nil)
                                                        warningMessage:NSLocalizedString(@"WasActionWarning", nil)] autorelease]];
         [self addPoisonWord:[[[SSPoisonWord alloc] initWithPoisonWord:NSLocalizedString(@"Not", nil)
                                                        warningMessage:NSLocalizedString(@"NotActionWarning", nil)] autorelease]];
      }
      
      [self registerForAllEventNotifications];
      
      [self updateFilteredActorArray];

      currentLinkFromEvent = nil;
   }

   return self;
}

//***********************************
- (void)dealloc
{
   [[NSNotificationCenter defaultCenter] removeObserver:self];

   //so that all events will be released
   [eventArray makeObjectsPerformSelector:@selector(removeAllRelatedNeedsDiamonds)];
   [eventArray makeObjectsPerformSelector:@selector(removeAllLinks)]; 

   [aalosDictionary release];
   [dataSourceDictionary release];
   [alphabeticDataSourceDictionary release];
   [structureDictionary release];
   [eventArray release];
   [commentArray release];
   [needsDiamondArray release];
   [defaultNeedsDiamondValues release];
   [super dealloc];
}


@end
